<script>
/**
 * 参考
 * http://www.umyui.com/umycomponent/u-table-api
 */
import { v4 } from "uuid";
import { merge, isFunction, cloneDeep } from "lodash";
import mixinTable from "./mixinTable.js";
import siteMixin from "../../siteMixin.js";
export default {
  mixins: [siteMixin, mixinTable],
  props: {
    tableOptions: {
      type: Object,
      default: () => ({
        columns: [],
        pageApiPromise: null, // 列表接口
        sortApiPromise: null, // 排序接口
      }),
    },
  },
  data() {
    return {
      formData: {},
      tableData: {
        total: 0,
        items: [],
        status_code: 200,
        count: 0,
      },
      paggingkey: v4(),
      pagging: {
        currentPage: 1,
        currentPageTotal: 50,
      },
      sort: {
        orderFiledName: undefined,
        orderFiledAsc: undefined,
      },
      selectedRows: [],
      config: {
        isLoading: false,
        totalSummaryLoading: false,
      },
      tableHeight: 10000,
      rowHeight: 48,
    };
  },
  watch: {
    "mergeTableOptionsSync.dicData": {
      deep: true,
      immediate: true,
      handler(newVal) {
        this.tableData.total = newVal.length;
        this.tableData.items = newVal;
      },
    },
    "mergeTableOptionsSync.loading": {
      immediate: true,
      handler(newVal) {
        this.config.isLoading = newVal;
      },
    },
  },
  computed: {
    axiosConfig() {
      return merge({}, this.formData, this.pagging, this.sort);
    },
    mergeTableOptionsSync() {
      return merge(
        {
          rowHeight: this.rowHeight,
          tableProps: {
            rowClassName: "", // 行的 class  的回调方法
            rowStyle: {}, // 行的 style  的回调方法
            cellClassName: "", // 行单元格的 className  的回调方法
            cellStyle: {}, // 行单元格的 style  的回调方法
            headerRowClassName: "", // 表头行的 className 的回调方法
            headerRowStyle: {}, // 表头行的 style 的回调方法
            headerCellClassName: "", // 表头单元格的 className 的回调方法
            headerCellStyle: {}, // 表头单元格的 style 的回调方法
          },
          loading: false,
          columns: [],
          pageApiPromise: null, // 列表接口
          sortApiPromise: null, // 排序接口
          dicData: [], // 给定具体表格数据
          pagination: true, //显示分页
          showHeader: true, // 显示表头
          useVirtual: false, // 表格只占一屏
          requestHandler: null,
          responseHandler: null,
          style: "", // 表格整体样式
          appendSummary: null, //重写底部
          rowClassName: this.rowClassName, // 行的 className 的回调方法，也可以使用字符串为所有行设置一个固定的 className。
          pageChange: this.pageChange,
          expandChange: () => {}, // 展开事件
          resetData: () => {}, // 表格数据处理方法
          customerData: false,
        },
        this.tableOptions
      );
    },
    columnsSync() {
      return this.tableOptions.columns
        .filter((column) => {
          if (!column) return false;
          const visiable = isFunction(column.visiable)
            ? column.visiable()
            : column.visiable;
          return visiable !== false;
        })
        .map((column) => {
          return {
            props: {
              width: column.width,
              dicData: column.dicData,
              render: column.render,
              align: "center",
              style: "", // 自定style
              showOverflowTooltip: false,
              groupUniqueKey: null, // 合并行key
              groupRow: false, // 合并行横着排
              copy: false, // 复制按钮
              view: false, // 查看按钮
              edit: false, // 编辑按钮
              onClick: null, // 点击事件
              picture: false, // 图片格式化
              money: false, // 格式化金额两位小数
              integer: false, //合计行，统计为整数
              summary: false, // 显示底部合计
              time: false, // 时间格式化
              sortable: false, //显示排序
              zero: true, // "0" 显示 --
              perm: "true", // 权限名称，从this.$store.state中取得
              selectable: (row, index) => true, // 勾选列能否被勾选
              className: "aone-table-column-" + column.prop,
              labelClassName: "",
              ...column,
            },
          };
        })
        .map((column) => {
          if (column.props.sortable) {
            column.props.sortable = "string";
          }
          if (column.props.tooltip) {
            column.props.showOverflowTooltip = true;
          }
          if (typeof column.props.perm == "boolean") {
            column.props.perm = "" + column.props.perm;
          }
          return column;
        });
    },
    paggingSync() {
      return {
        props: {
          pageSizes: [50, 100, 300, 500, 800, 1000],
          currentPage: this.pagging.currentPage,
          pageSize: this.pagging.currentPageTotal,
          total: this.tableData.total,
          layout: "prev, pager, next, sizes, jumper, total",
        },
        on: {
          "current-change": (currentPage) => {
            this.pagging.currentPage = currentPage;
            this.reload();
          },
          "size-change": (pageSize) => {
            this.pagging.currentPage = 1;
            this.pagging.currentPageTotal = pageSize;
            this.reload();
          },
        },
      };
    },
  },
  methods: {
    search(formData = {}) {
      this.pagging.currentPage = 1;
      this.formData = formData;
      this.beforeRequest();
    },
    reload() {
      this.formData = this.axiosConfig;
      this.beforeRequest();
    },
    reset() {
      this.pagging.currentPage = 1;
      this.formData = this.axiosConfig;
      this.paggingkey = v4();
      this.beforeRequest();
    },
    mergeRequestHandler() {
      const context = this.$parent;
      let params = [this.axiosConfig, this.axiosConfig, this.axiosConfig];
      if (isFunction(this.mergeTableOptionsSync.requestHandler)) {
        params = this.mergeTableOptionsSync.requestHandler.bind(context)(
          cloneDeep(this.axiosConfig),
          cloneDeep(this.axiosConfig),
          cloneDeep(this.axiosConfig)
        );
        if (!Array.isArray(params)) {
          params = [params];
        }
      }
      return params;
    },
    async beforeRequest() {
      if (this.config.isLoading) return;
      this.selectedRows = [];
      const params = this.mergeRequestHandler();
      // 返回false终止请求列表
      if (params.length && params[0] === false) {
        return;
      }
      let httpResponseArray = null;
      // pageApiPromise 可以传多个api地址
      if (this.mergeTableOptionsSync.pageApiPromise) {
        this.config.isLoading = true;
        const apiList = Array.isArray(this.mergeTableOptionsSync.pageApiPromise)
          ? this.mergeTableOptionsSync.pageApiPromise
          : [this.mergeTableOptionsSync.pageApiPromise];
        httpResponseArray = await Promise.all(
          apiList.map((api, idx) => api(params[idx]))
        ).finally(() => {
          this.config.isLoading = false;
        });
      } else if (
        Array.isArray(this.mergeTableOptionsSync.dicData) &&
        this.mergeTableOptionsSync.dicData.length
      ) {
        httpResponseArray = {
          total: this.mergeTableOptionsSync.dicData.length,
          items: this.mergeTableOptionsSync.dicData,
          status_code: 200,
          count: 0,
        };
      }
      if (httpResponseArray) {
        this.$nextTick(() => {
          const formatResponse = this.afterResponse(httpResponseArray);
          // 有些接口返回不是items，而是list
          if (!formatResponse.items && Array.isArray(formatResponse.list)) {
            formatResponse.items = formatResponse.list;
          }
          this.tableData.total =
            formatResponse.total || formatResponse.items.length;
          // 判断是否有需要处理数据
          if (this.mergeTableOptionsSync.customerData) {
            this.mergeTableOptionsSync.resetData(
              formatResponse.items,
              formatResponse.sum || null
            );
          } else {
            this.tableData.items = formatResponse.items;
          }
        });
      }
    },
    afterResponse(httpResponseArray) {
      const context = this.$parent;
      if (isFunction(this.mergeTableOptionsSync.responseHandler)) {
        return this.mergeTableOptionsSync.responseHandler.apply(
          context,
          httpResponseArray
        );
      }
      return Array.isArray(httpResponseArray)
        ? httpResponseArray[0]
        : httpResponseArray;
    },
    renderSummaries({ columns, data }) {
      const defaultSummary = this.getSummaries(this.columnsSync, {
        columns,
        data,
      });
      if (!this.mergeTableOptionsSync.appendSummary) return [defaultSummary];
      const newFooterArray = this.mergeTableOptionsSync.appendSummary.bind(
        this.$parent
      )({ columns, data }, this.columnsSync);
      for (let i = newFooterArray.length - 1; i > 0; i--) {
        if (newFooterArray[i].length > 1 && newFooterArray[i][0] === null) {
          newFooterArray[i][0] = newFooterArray[i - 1][0];
          newFooterArray[i - 1] = newFooterArray[i];
          newFooterArray[i] = [null];
        }
      }
      if (this.config.totalSummaryLoading && newFooterArray.length) {
        for (let i = 1; i < newFooterArray.length; i++) {
          if (newFooterArray[i]) {
            newFooterArray[i] = (
              <span>
                {newFooterArray[i]}
                {this.iconLoading()}
              </span>
            );
          }
        }
      }
      return [defaultSummary, newFooterArray];
    },
    renderTable() {
      // 是否显示底部合计
      const showSummary =
        this.tableData.items.length &&
        this.columnsSync.find((it) => it.props.summary);
      const tableProps = this.buildProps();
      const style = "width: 100%;" + this.mergeTableOptionsSync.style;
      return (
        <u-table
          data={this.tableData.items}
          border
          ref="xTable"
          style={style}
          column-key
          rowHeight={this.mergeTableOptionsSync.rowHeight}
          maxHeight={this.tableHeight}
          useVirtual={this.mergeTableOptionsSync.useVirtual}
          class={{
            "el-table-summary": showSummary,
            "el-table-onpage": this.mergeTableOptionsSync.useVirtual,
            "el-table-mulpage": !this.mergeTableOptionsSync.useVirtual,
            "el-table-hide-header": !this.mergeTableOptionsSync.showHeader,
          }}
          v-loading={this.config.isLoading}
          element-loading-text={$AONE_LAN.loading}
          element-loading-spinner="el-icon-loading"
          customClass="aone-table-loading"
          show-summary={!!showSummary}
          summary-method={this.renderSummaries}
          empty-text={$AONE_LAN.emptyText}
          {...{
            props: tableProps,
            on: {
              "sort-change": this.sortChange,
              "selection-change": this.selectionChange,
              "expand-change": this.mergeTableOptionsSync.expandChange,
            },
          }}
        >
          {this.renderTableColumn()}
        </u-table>
      );
    },
    renderTableColumn() {
      const allColumnSlots = this.columnsSync.map((column) => {
        // 列渲染优先级  render > dicData > prop
        const { props: columnProps } = column;
        const context = this.$parent;

        const operateRender = (node, row) => {
          node =
            node === undefined ||
            node === null ||
            (Array.isArray(node) && !node.length)
              ? "--"
              : node;
          if (
            columnProps.perm !== "true" &&
            columnProps.perm &&
            !this.$store.state[columnProps.perm]
          ) {
            columnProps.onClick = null;
          }
          return (
            <div
              class={{
                "flex-row": columnProps.align == "left",
                "flex-center-row": columnProps.align == "center",
              }}
            >
              <div
                class={{
                  "flex-1": true,
                  line: columnProps.onClick,
                  cursor: columnProps.onClick,
                }}
                onClick={() =>
                  columnProps.onClick && columnProps.onClick.bind(this)(row)
                }
              >
                {node}
              </div>
              <div class="flex-row">
                {this.vif(columnProps.copy)(
                  <i
                    class="el-icon-document-copy"
                    onClick={() => {
                      this.doCopy(row[columnProps.prop]);
                    }}
                    title={$AONE_LAN.copy}
                  />
                )}
                {this.vif(columnProps.view)(
                  <i
                    class="el-icon-view"
                    onClick={() =>
                      columnProps.onClick && columnProps.onClick.bind(this)(row)
                    }
                    title={$AONE_LAN.view}
                  />
                )}
                {this.vif(columnProps.edit)(
                  <i
                    class="el-icon-edit-outline"
                    onClick={() =>
                      columnProps.onClick && columnProps.onClick.bind(this)(row)
                    }
                    title={$AONE_LAN.edit}
                  />
                )}
              </div>
            </div>
          );
        };

        const jsxRender = (row) => {
          let resultNode = null;
          let renderType = 0;
          const nodeClassNameList = [];
          const styleArray = (columnProps.style?.split(";") || []).filter(
            Boolean
          );
          if (isFunction(columnProps.render)) {
            resultNode = columnProps.render.bind(context)(row); // 保持与外部页面this统一
          } else if (Array.isArray(columnProps.dicData)) {
            const item = columnProps.dicData.find(
              (it) => it.value == row[columnProps.prop]
            );
            if (item.color) {
              styleArray.push(`color:${item.color}`);
            }
            resultNode = item.label;
          } else if (columnProps.money) {
            // 金额格式化
            resultNode = this.$tool.formatNum(row[columnProps.prop] || 0, true);
          } else if (columnProps.time) {
            // 时间格式化
            resultNode = this.$tool.timer(
              new Date(row[columnProps.prop] * 1000),
              true
            );
          } else if (columnProps.picture) {
            // 金额格式化
            resultNode = (
              <el-image
                style="height: 30px"
                src={row[columnProps.prop]}
                preview-src-list={[row[columnProps.prop]]}
              ></el-image>
            );
          } else {
            // 字段返回空，显示--
            resultNode = row[columnProps.prop];
            renderType = 1;
          }
          if (columnProps.zero && resultNode == "0") {
            // 字段返回字符串0，则显示--
            resultNode = null;
          }
          if (resultNode) {
            if (renderType == 1 && columnProps.showOverflowTooltip) {
              nodeClassNameList.push("overflow-ellipsis");
            }
          }
          return resultNode !== null && resultNode !== undefined ? (
            <div style={styleArray.join(";")} class={nodeClassNameList}>
              {resultNode}
            </div>
          ) : null;
        };
        let scopedSlots = {};
        // 第一列全选列
        if (columnProps.type != "selection") {
          scopedSlots = {
            default: ({ row }) => {
              const h = this.$createElement;
              const content = operateRender(jsxRender(row), row);
              const vNode = (
                <div class="anoe-table-cell" style={columnProps.style}>
                  {content}
                </div>
              );
              vNode.content = content;
              return vNode;
            },
          };
        }
        return {
          columnProps,
          scopedSlots,
        };
      });
      const groupColumns = [];
      // 列合并
      allColumnSlots.forEach((column) => {
        if (!column._used) {
          let theGroups = [column];
          if (column.columnProps.groupUniqueKey) {
            theGroups = allColumnSlots.filter(
              (it) =>
                it.columnProps.groupUniqueKey ===
                column.columnProps.groupUniqueKey
            );
          }
          const mergeOneColumn = theGroups.reduce((p, c) => {
            c._used = true;
            if (!p) return c;
            let labelClassName =
              this.sort.orderFiledName == p.columnProps.prop
                ? "scl-" + this.sort.orderFiledAsc
                : "";
            const renderHeader = () => {
              // 这里没写p,c的renderHeader，后续有需要再补上
              const labelVNode = [
                p.columnProps.label,
                c.columnProps.label ? "/" : null,
                c.columnProps.label ? c.columnProps.label : null,
              ];
              // 左右都要排序按钮
              if (p.columnProps.sortable && c.columnProps.sortable) {
                labelVNode.unshift(
                  <span class="caret-wrapper left-caret-wrapper">
                    <i
                      class="sort-caret ascending"
                      onClick={() => {
                        this.sortChange({
                          prop: p.columnProps.prop,
                          order: "ascending",
                        });
                      }}
                    ></i>
                    <i
                      class="sort-caret descending"
                      onClick={() => {
                        this.sortChange({
                          prop: p.columnProps.prop,
                          order: "descending",
                        });
                      }}
                    ></i>
                  </span>
                );
              }
              return (
                <span onClick={(e) => e.stopPropagation()}>{labelVNode}</span>
              );
            };
            return {
              columnProps: {
                ...p.columnProps,
                ...c.columnProps,
                labelClassName,
                sortable: p.columnProps.sortable || c.columnProps.sortable,
                renderHeader: renderHeader,
                width: Math.max(p.columnProps.width, c.columnProps.width),
              },
              scopedSlots: {
                default: (scope) => {
                  // 横着排
                  if (p.columnProps.groupRow) {
                    const pNode = p.scopedSlots.default(scope);
                    const cNode = c.scopedSlots.default(scope);
                    if (pNode.content == "--" && cNode.content == "--") {
                      return <div class="flex-center-row">{pNode}</div>;
                    }
                    return (
                      <div class="flex-center-row">
                        {pNode}
                        <span class="padding-2">/</span>
                        {cNode}
                      </div>
                    );
                  }
                  // 竖着排
                  else {
                    const pNode = p.scopedSlots.default(scope);
                    const cNode = c.scopedSlots.default(scope);
                    if (pNode.content == "--" && cNode.content == "--") {
                      return <div class="flex-center-column">{pNode}</div>;
                    }
                    return (
                      <div class="flex-center-column">
                        {pNode}
                        {cNode}
                      </div>
                    );
                  }
                },
              },
            };
          });
          groupColumns.push(mergeOneColumn);
        }
      });
      const readyGroupColumns = groupColumns.map((column) => {
        return {
          column,
          jsx: (
            <u-table-column
              {...{
                props: column.columnProps,
              }}
              scopedSlots={column.scopedSlots}
            ></u-table-column>
          ),
        };
      });
      // 二级表头合并
      const secondLabelColumns = [];
      readyGroupColumns.forEach(({ column, jsx, _used }) => {
        if (_used) return;
        if (!column.columnProps.parentLabelKey) {
          secondLabelColumns.push(jsx);
        } else {
          // 选出当前相关二级表头的key
          const fls = readyGroupColumns.filter(
            (it) =>
              it.column.columnProps.parentLabelKey ===
              column.columnProps.parentLabelKey
          );
          let parentLabel = fls.find((it) => it.column.columnProps.parentLabel);
          if (parentLabel) {
            parentLabel = parentLabel.column.columnProps.parentLabel;
          }
          secondLabelColumns.push(
            <u-table-column
              label={parentLabel}
              render-header={column.columnProps.parentRenderHeader}
              align="center"
            >
              {fls.map((it) => it.jsx)}
            </u-table-column>
          );
          fls.forEach((it) => (it._used = true));
        }
      });
      return secondLabelColumns;
    },
    renderPageing() {
      if (!this.mergeTableOptionsSync.pagination) return null;
      return (
        <div class="aone-table-pagger">
          <el-pagination
            key={this.paggingkey}
            background
            {...{
              props: this.paggingSync.props,
              on: this.paggingSync.on,
            }}
          ></el-pagination>
        </div>
      );
    },
    renderTip() {
      if (this.tableOptions.tipColumn !== undefined) {
        return this.tableOptions.tipColumn();
      }
    },
    renderHeader() {
      if (this.tableOptions.headerColumn !== undefined) {
        return this.tableOptions.headerColumn();
      }
    },
  },
  render(h) {
    return (
      <div class="aone-table">
        {this.renderHeader()}
        {this.renderTable()}
        {this.renderTip()}
        {this.renderPageing()}
        {this.renderGuangBiao()}
      </div>
    );
  },
  updated() {
    this.$nextTick(() => {
      this.calcTableHeight();
    });
  },
};
</script>
<style lang="scss" scoped>
.aone-table {
  /deep/ {
    .anoe-table-cell {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
      width: 100%;
      cursor: initial;
      .overflow-ellipsis {
        width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
    .el-table .el-table__cell {
      padding: 9px 0;
    }
    .el-pagination__jump {
      margin-left: 0;
    }
    .el-pagination__total {
      margin-left: 10px;
    }
    .plTableBox .el-table td,
    .plTableBox .el-table th {
      padding: 8px 0;
    }
  }
  .aone-table-pagger {
    box-sizing: border-box;
    background-color: #f8f8f9;
    padding: 5px;
    margin-top: 5px;
  }
  .el-table-hide-header {
    /deep/ {
      .el-table__fixed-header-wrapper,
      .el-table__header-wrapper {
        display: none;
      }
    }
  }
}
/deep/ div[customclass="aone-table-loading"] {
  .el-loading-mask {
    background: #0004;
    position: fixed;
    top: 0;
    z-index: 99999;
    left: 0;
    height: 100vh;
    .el-loading-spinner {
      .el-icon-loading {
        color: #0b81ff;
        font-size: 20px;
      }
      .el-loading-text {
        color: #0b81ff;
      }
    }
  }
}
// /deep/ {
//   .el-table__header-wrapper,
//   .el-table__fixed-header-wrapper,
//   .el-table__fixed-header-wrapper {
//     .cell {
//       font-family: monospace;
//     }
//   }
// }
</style>
